package qc.module.cms.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import qc.common.core.constants.QCConstant;
import qc.common.core.enums.CmsArticleContentTypeEnum;
import qc.common.core.enums.CmsArticleOperateTypeEnum;
import qc.common.core.enums.CmsArticleStatusFlagEnum;
import qc.common.core.enums.CmsArticleTagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.common.core.utils.DateUtil;
import qc.module.cms.dto.article.*;
import qc.module.cms.dto.category.CategoryDto;
import qc.module.cms.dto.swipper.SwipperDto;
import qc.module.cms.entity.Article;
import qc.module.cms.entity.CategorySwipper;
import qc.module.cms.mapper.ArticleMapper;
import qc.module.cms.repository.ArticleRepository;
import qc.module.platform.dto.file.FileInfoDto;
import qc.module.platform.dto.uac.UacUserInfoDto;

import java.util.*;
import java.util.stream.Collectors;

/**
 * ArticleService
 *
 * @author QuCheng Tech
 * @since 2023/5/26
 */
@Service
public class ArticleService {
    private ArticleRepository repository;

    @Autowired
    public void setArticleRepository(ArticleRepository repository) {
        this.repository = repository;
    }

    private CategoryService categoryService;

    @Autowired
    public void setCategoryService(CategoryService categoryService) {
        this.categoryService = categoryService;
    }

    private CategoryDeptService categoryDeptService;

    @Autowired
    public void setCategoryDeptService(CategoryDeptService categoryDeptService) {
        this.categoryDeptService = categoryDeptService;
    }

    private CategorySwipperService categorySwipperService;

    @Autowired
    public void setCategorySwipperService(CategorySwipperService categorySwipperService) {
        this.categorySwipperService = categorySwipperService;
    }

    private ArticleLogService articleLogService;

    @Autowired
    public void setArticleLogService(ArticleLogService articleLogService) {
        this.articleLogService = articleLogService;
    }

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;
    /**
     * 获取Top-N文章的数量，默认为6
     */
    private static final int Get_Top_N_Article_Defalut_Count = 0x6;

    /**
     * 查询文章列表，根据用户所在部门进行筛选过滤
     *
     * @param condition      查询条件，可输入关键字、栏目、起止时间范围
     * @param userAllDeptIds 查询的用户所在所有部门ID集合
     * @return 文章列表，包含分页信息，文章不包含内容信息
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public ArticleQueryResultDto query(ArticleQueryConditionDto condition, List<Integer> userAllDeptIds) throws QCPromptException {
        //根据传入的用户所在部门ID集合，在栏目与部门关联关系中取交集，得到可访问的栏目ID集合
        List<Integer> filterCategoryIds = categoryDeptService.getValidCategoryIds(userAllDeptIds);

        //构造查询文章列表的文章状态集合
        List<CmsArticleStatusFlagEnum> articleStatusFlags = new ArrayList<>();
        articleStatusFlags.add(CmsArticleStatusFlagEnum.DRAFT);
        articleStatusFlags.add(CmsArticleStatusFlagEnum.AUDIT);
        articleStatusFlags.add(CmsArticleStatusFlagEnum.PASS);
        articleStatusFlags.add(CmsArticleStatusFlagEnum.NO_PASS);
        articleStatusFlags.add(CmsArticleStatusFlagEnum.REVIEW_PASS);
        articleStatusFlags.add(CmsArticleStatusFlagEnum.REVIEW_NO_PASS);
        //已发布的也需要显示，无法进行修改操作
        articleStatusFlags.add(CmsArticleStatusFlagEnum.PUBLISH);
        articleStatusFlags.add(CmsArticleStatusFlagEnum.RECALL);
        //是否需要包含已删除
        //articleStatusFlags.add(CmsArticleStatusFlagEnum.DELETED);

        return query(filterCategoryIds, articleStatusFlags, condition);
    }

    /**
     * 获取待审核文章列表
     *
     * @param condition      查询条件，可输入关键字、栏目、起止时间范围
     * @param userAllDeptIds 查询的用户所在所有部门ID集合
     * @return 待审核文章列表，文章不包含内容信息
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public ArticleQueryResultDto getNeedAudit(ArticleQueryConditionDto condition, List<Integer> userAllDeptIds) throws QCPromptException {
        //根据传入的用户所在部门ID集合，在栏目与部门关联关系中取交集，得到可访问的栏目ID集合
        List<Integer> filterCategoryIds = categoryDeptService.getValidCategoryIds(userAllDeptIds);
        //构造查询文章列表的文章状态集合
        List<CmsArticleStatusFlagEnum> articleStatusFlags = new ArrayList<>();
        //待审核列表中不显示状态为草稿的文章
        if (condition.getAudit() != null && condition.getAudit() == 0x1){
            //二审，只查询待审核、二审通过，二审不通过
            articleStatusFlags.add(CmsArticleStatusFlagEnum.AUDIT);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.REVIEW_PASS);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.REVIEW_NO_PASS);
            //已发布的也需要显示，无法进行修改操作，可以进行撤回操作
            articleStatusFlags.add(CmsArticleStatusFlagEnum.PUBLISH);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.RECALL);
        }else{
            //其它为终审
            //articleStatusFlags.add(CmsArticleStatusFlagEnum.DRAFT);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.AUDIT);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.PASS);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.NO_PASS);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.REVIEW_PASS);
            //articleStatusFlags.add(CmsArticleStatusFlagEnum.REVIEW_NO_PASS);
            //已发布的也需要显示，无法进行修改操作，可以进行撤回操作
            articleStatusFlags.add(CmsArticleStatusFlagEnum.PUBLISH);
            articleStatusFlags.add(CmsArticleStatusFlagEnum.RECALL);
            //是否需要包含已删除
            //articleStatusFlags.add(CmsArticleStatusFlagEnum.DELETED);
        }

        return query(filterCategoryIds, articleStatusFlags, condition);
    }

    /**
     * 查询敏感词匹配的文章，返回结果中包含匹配的敏感词信息
     *
     * @param condition 查询条件
     * @return List<ArticleDto>
     * @author QcCheng Tech
     * @since 2024/4/28
     */
    public List<ArticleDto> queryBySensitiveWords(SensitiveWordsQueryConditionDto condition) throws QCPromptException {
        
        //条件判空

        //查询数据
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        //指定为查询不包含附件列
        wrapper.select(Article::getId, Article::getCid, Article::getTitle,Article::getContent, Article::getCover, Article::getCtype, Article::getKeywords,
                Article::getSource, Article::getAuthor, Article::getIntm, Article::getInuser, Article::getIndept,
                Article::getUptm, Article::getUpuser, Article::getPubtm, Article::getPubuser, Article::getPubdept,
                Article::getFlag, Article::getTags, Article::getCount,Article::getReviewtm,Article::getReviewuser,Article::getReviewdept);

        //查询条件--指定状态标记
        wrapper.in(Article::getFlag, CmsArticleStatusFlagEnum.PUBLISH);
        
        //判断输入参数condition
        if (condition != null) {
            // 判断condition中的时间
            if (StringUtils.isNotBlank(condition.getBegintm())) {
                Date date = DateUtil.parseDate(condition.getBegintm());
                wrapper.ge(Article::getIntm, date);
            }
            if (StringUtils.isNotBlank(condition.getEndtm())) {
                Date date = DateUtil.parseDate(condition.getEndtm());
                wrapper.le(Article::getIntm, date);
            }
            // 判断condition中国的敏感词集合
            if (CollectionUtils.isNotEmpty(condition.getSensitivewords())){
                wrapper.and(q -> {
                    for (String sensitivewords : condition.getSensitivewords()){
                        q.like(Article::getContent, sensitivewords).or();
                    }
                });
            }
        }

        //排序
        //先根据标签降序，文章置顶时标签为8，可以保证置顶文章排在最前
        wrapper.orderByDesc(Article::getTags);
        //再按发布时间降序，最新发布的文章排在前面
        wrapper.orderByDesc(Article::getIntm);

        List<ArticleDto> result = new ArrayList<>();

        List<Article> ens = repository.selectList(wrapper);
        if (ens != null && ens.size() > 0x0) {
            List<Integer> cids = ens.stream().map(Article::getCid).collect(Collectors.toList());
            List<CategoryDto> categoryDtos = categoryService.getByIdsBatch(cids,false);
            
            //result = ArticleMapper.MAPPER.toDtoList(ens);
            //返回结果中匹配的敏感词返回处理
            for (Article article : ens){
                ArticleDto dto = new ArticleDto();
                dto = ArticleMapper.MAPPER.toDto(article);
                String words = "";
                if (CollectionUtils.isNotEmpty(condition.getSensitivewords())){
                    for (String sensitivewords : condition.getSensitivewords()){
                        if (article.getContent().contains(sensitivewords)){
                            words += sensitivewords + ",";
                        }
                    }
                }
                if (words.endsWith(",")){
                    words = StringUtils.removeEnd(words,",");// 去掉字符串最后一个逗号
                }
                dto.setSensitivewords(words);
                dto.setContent(null);

                CategoryDto categoryDto = categoryDtos.stream().filter(category -> category.getId() == article.getCid())
                        .findAny().orElse(null);
                if (categoryDto != null) dto.setAuditcount(categoryDto.getAuditcount());
                
                result.add(dto);
            }
            
        }
        
        return result;
    }

    /**
     * 敏感词替换
     *
     * @param dto 查询条件
     * @return 成功返回null，失败返回提示信息
     * @author QcCheng Tech
     * @since 2024/4/29
     */
    public String replaceSensitiveWords(ReplaceSensitiveWordsDto dto,UacUserInfoDto userInfo){
        //判空
        if (dto == null) return QCUnifyReturnValue.Warn("条件对象不能为空");
        if (CollectionUtils.isEmpty(dto.getArticleids())) return QCUnifyReturnValue.Warn("文章id不能为空");
        if (dto.getSensitivereplacewords() == null || dto.getSensitivereplacewords().isEmpty()) 
            return QCUnifyReturnValue.Warn("敏感词对象不能为空"); 
        
        //替换成功文章篇数与替换失败文章篇数
        int successCount = 0x0;
        int failCount = 0x0;

        //只查询content
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Article::getId,Article::getContent);
        queryWrapper.in(Article::getId,dto.getArticleids());
        List<Article> articles = repository.selectList(queryWrapper);
        
        if (CollectionUtils.isNotEmpty(articles)){
            for (Article article : articles){
                String senstivewords = "";
                String replacewords = "";
                for (Map.Entry<String,String> entry : dto.getSensitivereplacewords().entrySet()){
                    System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());
                    //如果文章内容中有敏感词，替换文章内容中的敏感词
                    if (article.getContent().contains(entry.getKey())){
                        article.setContent(article.getContent().replace(entry.getKey(),entry.getValue()));
                        //记录敏感词和替换词
                        senstivewords += entry.getKey() + ",";
                        replacewords += entry.getValue() + ",";
                    }
                }
                //替换敏感词
                LambdaUpdateWrapper<Article> wrapper = new LambdaUpdateWrapper<>();
                wrapper.set(Article::getContent,article.getContent());
                wrapper.eq(Article::getId,article.getId());
                if (repository.update(article,wrapper) < 0x1){
                    failCount ++;
                }else {
                    successCount ++;
                }
                
                //记录文章操作日志
                if (senstivewords.endsWith(","))
                    senstivewords = StringUtils.removeEnd(senstivewords,",");// 去掉字符串最后一个逗号
                if (replacewords.endsWith(","))
                    replacewords = StringUtils.removeEnd(replacewords,",");// 去掉字符串最后一个逗号
                
                articleLogService.add(article.getId(),CmsArticleOperateTypeEnum.REPLACE_SENSITIVE_WORDS,
                        "敏感词：" + senstivewords + "  替换词：" + replacewords,userInfo);
            }
        }
            
        return QCUnifyReturnValue.Success("替换成功" + successCount +"篇文章，替换失败" + failCount + "篇文章。");
    }

    /**
     * 文章公用查询方法，根据指定文章状态集合和查询条件进行查询
     *
     * @param userAllDeptCategoryIds 用户有权限的所有栏目ID集合
     * @param articleStatusFlags     文章状态集合
     * @param condition              查询条件，包含分页信息，可指定栏目ID、关键字、起止时间
     * @return 返回结果中包含分页信息，文章信息不包含内容
     * @author QuCheng Tech
     * @since 2023/5/30
     */
    ArticleQueryResultDto query(List<Integer> userAllDeptCategoryIds, List<CmsArticleStatusFlagEnum> articleStatusFlags, ArticleQueryConditionDto condition) throws QCPromptException {
        if (userAllDeptCategoryIds == null || userAllDeptCategoryIds.size() < 0x1)
            throw new QCPromptException("当前用户无任何有效的栏目信息");
        if (articleStatusFlags == null || articleStatusFlags.size() < 0x1)
            throw new QCPromptException("查询指定的文章状态不能为空");
        //如果筛选后得到的栏目ID集合为空，需要返回信息，表示指定的查询条件查询不到信息，设置总数为0
        ArticleQueryResultDto result = new ArticleQueryResultDto();
        result.setTotal(0x0);
        result.setPages(0x1);
        result.setItems(new ArrayList<>());
        if (userAllDeptCategoryIds != null && userAllDeptCategoryIds.size() > 0x0) {
            //查询数据
            LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
            //指定查询列
            //指定为查询所有列
            //wrapper.select(Article::getId, Article::getCid, Article::getTitle, Article::getCtype, Article::getKeywords, Article::getContent, Article::getSource, Article::getAuthor, Article::getIntm, Article::getInuser, Article::getUptm, Article::getUpuser,Article::getPubtm,Article::getPubuser,Article::getPubdept, Article::getOdr, Article::getFlag, Article::getCount);
            //指定为查询不包含内容列和附件列
            wrapper.select(Article::getId, Article::getCid, Article::getTitle, Article::getCover, Article::getCtype, Article::getKeywords,
                    Article::getSource, Article::getAuthor, Article::getIntm, Article::getInuser, Article::getIndept,
                    Article::getUptm, Article::getUpuser, Article::getPubtm, Article::getPubuser, Article::getPubdept,
                    Article::getFlag, Article::getTags, Article::getCount,Article::getReviewtm,Article::getReviewuser,Article::getReviewdept);

            //查询条件--指定状态标记
            wrapper.in(Article::getFlag, articleStatusFlags);
            //判断输入参数condition
            //如果condition中指定了栏目ID，构造eq条件，不需要使用传入的栏目ID集合
            int categoryId = 0x0;
            if (condition != null) {
                // 判断condition中的栏目ID
                if (!StringUtils.isBlank(condition.getCid())) {
                    categoryId = Integer.parseInt(condition.getCid());
                    // 判断输入的栏目ID是否在当前用户可查权限内
                    if (!userAllDeptCategoryIds.contains(categoryId)) {
                        throw new QCPromptException("用户查询该栏目下的文章权限不足！");
                    }
                    // condition中指定了栏目ID
                    wrapper.eq(Article::getCid, categoryId);
                } else {
                    // 查询栏目id为空时，使用用户可查权限内的所有栏目ID
                    wrapper.in(Article::getCid, userAllDeptCategoryIds);
                }

                // 判断condition中的关键字
                if (StringUtils.isNotBlank(condition.getKeywords())) {
                    // like 标题或关键字
                    wrapper.and(q -> {
                        q.like(Article::getTitle, condition.getKeywords()).or().like(Article::getKeywords, condition.getKeywords());
                    });
                }

                // 判断condition中的作者
                if (StringUtils.isNotBlank(condition.getAuthor())) {
                    // like 来源或作者
                    wrapper.and(q -> {
                        q.like(Article::getSource, condition.getAuthor()).or().like(Article::getAuthor, condition.getAuthor());
                    });
                }

                // 判断condition中的时间
                if (StringUtils.isNotBlank(condition.getBegintm())) {
                    Date date = DateUtil.parseDate(condition.getBegintm());
                    wrapper.ge(Article::getIntm, date);
                }
                if (StringUtils.isNotBlank(condition.getEndtm())) {
                    Date date = DateUtil.parseDate(condition.getEndtm());
                    wrapper.le(Article::getIntm, date);
                }

                //判断是否指定了只查询有封面图片ID的文章
                if (condition.getHasCover() != null && condition.getHasCover().booleanValue() == true) {
                    wrapper.isNotNull(Article::getCover);
                    wrapper.gt(Article::getCover, 0x0);
                }
            } else {
                // condition为空时，使用用户可查权限内的所有栏目ID
                wrapper.in(Article::getCid, userAllDeptCategoryIds);
            }
            //排序
            //先根据标签降序，文章置顶时标签为8，可以保证置顶文章排在最前
            wrapper.orderByDesc(Article::getTags);
            //再按发布时间降序，最新发布的文章排在前面
            wrapper.orderByDesc(Article::getIntm);

            //分页查询
            // 先构造一个Page对象
            int pageNum = QCConstant.PAGEING_DEFAULT_PAGE_NUM;
            int pageSize = QCConstant.PAGEING_DEFAULT_PAGE_SIZE;
            if (condition != null) {
                if (condition.getPage() > 0x0)
                    pageNum = condition.getPage();
                if (condition.getPageSize() > 0x0)
                    pageSize = condition.getPageSize();
            }

            IPage<Article> page = new Page<>(pageNum, pageSize);
            IPage<Article> pageResult = repository.selectPage(page, wrapper);
            //获取查询结果
            result.setTotal(pageResult.getTotal());
            result.setPages(pageResult.getPages());
            List<Article> ens = pageResult.getRecords();
            if (ens != null && ens.size() > 0x0) {
                List<Integer> cids = ens.stream().map(Article::getCid).collect(Collectors.toList());
                List<CategoryDto> categoryDtos = categoryService.getByIdsBatch(cids,false);
                
                List<ArticleDto> articleDtos = ArticleMapper.MAPPER.toDtoList(pageResult.getRecords());
                for (ArticleDto dto : articleDtos){
                    CategoryDto categoryDto = categoryDtos.stream().filter(category -> category.getId() == dto.getCid())
                            .findAny().orElse(null);
                    if (categoryDto != null) dto.setAuditcount(categoryDto.getAuditcount());
                }
                result.setItems(articleDtos);
            }
        }

        return result;
    }

    /**
     * 获取指定ID的文字信息，包含内容
     *
     * @param articleId 文章ID
     * @return qc.module.cms.dto.article.ArticleDto
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public ArticleDto get(Integer articleId) throws QCPromptException {
        Article en = getEntity(articleId, true);
        ArticleDto dto = ArticleMapper.MAPPER.toDto(en);
        
        CategoryDto categoryDto = categoryService.get(dto.getCid(),false);
        if (categoryDto != null) dto.setAuditcount(categoryDto.getAuditcount());
        
        return dto;
    }

    /**
     * 获取指定ID的文字信息，包含内容
     *
     * @param articleId      文章ID
     * @param includeContent 是否包含文章内容
     * @return qc.module.cms.dto.article.Article
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public Article getEntity(Integer articleId, boolean includeContent) throws QCPromptException {
        if (articleId == null)
            throw new QCPromptException("文章ID不能为空");

        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        //不包含内容时指定查询列
        if (!includeContent)
            wrapper.select(Article::getId, Article::getCid, Article::getTitle, Article::getCover, Article::getCtype, Article::getKeywords,
                    Article::getSource, Article::getAuthor, Article::getIntm, Article::getInuser, Article::getIndept,
                    Article::getUptm, Article::getUpuser, Article::getPubtm, Article::getPubuser, Article::getPubdept,
                    Article::getFlag, Article::getTags, Article::getCount,Article::getReviewtm,Article::getReviewuser,Article::getReviewdept);

        wrapper.eq(Article::getId, articleId);

        Article en = repository.selectOne(wrapper);

        if (en == null)
            throw new QCPromptException("指定的文章不存在");

        return en;
    }

    /**
     * 查看指定文章信息，查看时自动将次数+1，包含内容
     *
     * @param articleId 文章ID
     * @return qc.module.cms.dto.article.ArticleDto
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public ArticleDto view(Integer articleId) throws QCPromptException {
        //调用get方法
        Article en = getEntity(articleId, true);

        //需要判断文章的状态，如果没有发布不需要对浏览次数进行+1
        if (en.getFlag() == CmsArticleStatusFlagEnum.PUBLISH) {
            LambdaUpdateWrapper<Article> wrapper = new LambdaUpdateWrapper<>();
            //次数+1
            wrapper.setSql("count=count+1");
            wrapper.eq(Article::getId, articleId);

            repository.update(null, wrapper);
        }
        
        ArticleDto articleDto = ArticleMapper.MAPPER.toDto(en);
        CategoryDto categoryDto = categoryService.get(en.getCid(),false);
        if (categoryDto != null) articleDto.setAuditcount(categoryDto.getAuditcount());

        return articleDto;
    }

    /**
     * 文章保存为草稿
     *
     * @param dto 文章信息，可以指定ID表示修改，不指定ID表示新增
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public String save(ArticleSaveDto dto, UacUserInfoDto userInfo) throws QCPromptException {
        if (dto == null)
            return QCUnifyReturnValue.Warn("文章对象不能为空");
        if (StringUtils.isBlank(dto.getTitle()))
            return QCUnifyReturnValue.Warn("文章标题不能为空");

        //DTO转换为Entity，并进行输入有效值判断
        Article en = new Article();
        //默认设置ID为0，后继根据ID判断是新增还是修改
        en.setId(0x0);
        //ID转换，用于修改时赋值，新增时在写入数据库前再生成新ID
        if (!StringUtils.isBlank(dto.getId())) {
            try {
                int id = Integer.parseInt(dto.getId());
                en.setId(id);
                //判断是否存在
                CmsArticleStatusFlagEnum existArticleStatusFlag = getArticleStatus(id);
                //验证是否能进行修改操作
                validStatusAndOperate(existArticleStatusFlag, CmsArticleOperateTypeEnum.DRAFT,0x0);
            } catch (NumberFormatException exception) {
            }
        }
        //文章所在栏目ID，需要判断栏目ID不能为空，并且栏目存在；同时获取栏目配置信息用于判断是否需要审核
        //栏目发布文章是否需要审核
        boolean categoryNeedAudit = true;
        if (dto.getCid() > 0x0) {
            CategoryDto categoryDto = categoryService.get(dto.getCid(), false);
            if (categoryDto == null)
                return QCUnifyReturnValue.Warn("指定文章所在的栏目不存在");

            //实体类栏目ID赋值
            en.setCid(dto.getCid());
            //栏目中的文章是否需要审核赋值
            //categoryNeedAudit = categoryDto.isAudit();
            categoryNeedAudit = categoryDto.getAuditcount() > 0x0 ? true : false;
        } else {
            return QCUnifyReturnValue.Warn("必须指定文章所在的栏目");
        }
        //文章标题
        en.setTitle(dto.getTitle());
        //处理文章内容类型，空值时使用默认
        Integer ctype = null;
        if (!StringUtils.isBlank(dto.getCtype())) {
            try {
                ctype = Integer.parseInt(dto.getCtype());
            } catch (NumberFormatException exception) {
                //转换错误不处理，使用默认状态
            }
        }
        en.setCtype(getCmsArticleContentTypeEnum(ctype));
        //文章关键字
        en.setKeywords(dto.getKeywords());
        //文章内容和附件，传入的内容放在内容中，传入的附件放到附件中；不管是否有输入均进行赋值，修改时可能出现将原有内容或附件清除的情况
        en.setContent(dto.getContent());
        en.setAttachment(dto.getAttachment());

        //文章封面ID需进行判空，非空时进行转换
        //方法同时作为新增和修改时的调用方法，如果在修改时将封面图片ID设置为空也需要对封面图片进行赋值，因此不需要进行大于0的判断
        en.setCover(dto.getCover());
        if (dto.getCover() > 0x0) {
            //图片是否有效需要调用platform中的接口进行判断，调用接口：/qc/file/get
            //判断文件无效设置文章的封面图片ID为0--表示为空
            if (!hasCoverExist(dto.getCover()))
                en.setCover(0x0);
        }
        //来源
        en.setSource(dto.getSource());
        //作者
        if (!StringUtils.isBlank(dto.getAuthor())) {
            en.setAuthor(dto.getAuthor());
        } else {
            en.setAuthor(userInfo.getName());
        }

        Date now = DateUtil.getNowDate();
        if (en.getId() == 0x0) {
            //新增文章，固定信息赋值
            //生成文章ID，获取数据库中的最大id+1后赋值
            en.setId(genereateId());
            //文章发布人、发布时间、发布部门，只有在新增时设置，更新时不进行修改
            en.setIntm(now);
            en.setInuser(userInfo.getName());
            en.setIndept(userInfo.getDeptName());
            //更新时间和更新人
            en.setUptm(now);
            en.setUpuser(userInfo.getName());
            //设置文章标记和浏览次数
            en.setFlag(categoryNeedAudit ? CmsArticleStatusFlagEnum.DRAFT : CmsArticleStatusFlagEnum.PUBLISH);
            
            en.setCount(0x0);
            en.setTags(0x0);

            if (repository.insert(en) < 0x1)
                return QCUnifyReturnValue.Warn("新增文章保存失败");
        } else {
            //修改文章
            //更新时间和更新人
            en.setUptm(now);
            en.setUpuser(userInfo.getName());
            //设置文章标记，需要根据栏目是否需要审核进行判断
            en.setFlag(categoryNeedAudit ? CmsArticleStatusFlagEnum.DRAFT : CmsArticleStatusFlagEnum.PUBLISH);
            if (repository.updateById(en) < 0x1)
                return QCUnifyReturnValue.Warn("修改文章保存失败");
        }

        //添加文章操作日志
        articleLogService.add(en.getId(), CmsArticleOperateTypeEnum.DRAFT, null, userInfo);

        //判断是否自动将文章发送到栏目轮播图中
        //判断文章有封面图片ID并且有效时才进行轮播图处理
        if (en.getCover() != null && en.getCover().intValue() > 0x0) {
            if (dto.getSwipperCid() > 0x0) {
                //判断栏目是否存在
                if (!categoryService.hasIdExist(dto.getSwipperCid()))
                    return QCUnifyReturnValue.Warn("文章保存成功。自动发布文章到轮播图时指定的栏目不存在。");

                //判断文章ID相同的信息是否存在
                CategorySwipper existSwipper = categorySwipperService.getEntityByArticleId(en.getId(), 0x0);
                if (existSwipper != null) {
                    //判断信息是否变化，仅需判断图片ID和标题
                    if (existSwipper.getFid() == null || existSwipper.getFid().intValue() != en.getCover().intValue()
                            || !StringUtils.equals(existSwipper.getTitle(), en.getTitle())) {
                        categorySwipperService.update(existSwipper.getId(), en.getCover(), en.getTitle());
                    }
                } else {
                    //新增轮播图
                    SwipperDto swipper = new SwipperDto();

                    swipper.setCid(dto.getSwipperCid());
                    swipper.setGroupid(0x0);//固定通过文章设置的轮播图分组ID为0
                    swipper.setFid(en.getCover());
                    swipper.setTitle(en.getTitle());
                    swipper.setArticleid(en.getId());

                    return categorySwipperService.add(swipper);
                }
            }
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 在其他项目中使用微服务之间调用方式, platform中的/qc/file/get方法返回封面文件信息,判断封面文件是否有效
     *
     * @param cover: 封面文件id
     * @return boolean true表示已存在，false表示不存在
     * @author QcCheng Tech
     * @date 2023/10/18
     */
    public boolean hasCoverExist(int cover) throws QCPromptException {
        List<ServiceInstance>  instances = discoveryClient.getInstances("module-platform");
        //如果获取到的微服务的实例数为0，抛出异常提示
        if(instances==null || instances.size()<0x1)
            throw new QCPromptException("调用module-platform微服务时无任何有效的实例。");

        ServiceInstance service = instances.get(0);
        String url = "http://" + service.getHost() + ":" + service.getPort() + "/file/get/" + cover;
        ResponseEntity<FileInfoDto> response = restTemplate.getForEntity(url, FileInfoDto.class);
        FileInfoDto fileInfoDto = response.getBody();
        if (fileInfoDto != null)
            return true;

        return false;
    }

    /**
     * 文章操作
     *
     * @param articleId   文章ID
     * @param operateType 操作类型
     * @param message     操作信息，可以为null
     * @param userInfo    操作的用户信息
     * @param isreview 是否为二审（审核通过/不通过操作时使用）
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/29
     * @update 2024/9/3 文章状态增加二审通过和二审不通过，修改相应操作 2024-9-30 文章操作类型去除二审通过和二审未通过
     */
    public String operate(Integer articleId, CmsArticleOperateTypeEnum operateType, String message,
                          UacUserInfoDto userInfo,boolean isreview) throws QCPromptException {
        //输入验证，审核不通过、发布撤回、二审未通过需要有填写信息
        if (operateType == CmsArticleOperateTypeEnum.NO_PASS || operateType == CmsArticleOperateTypeEnum.RECALL 
                //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
        ) {
            if (StringUtils.isBlank(message))
                return QCUnifyReturnValue.Warn("操作说明必须填写");
        }

        //获取文章信息，不包含内容
        Article en = getEntity(articleId, false);
        
        //获取文章栏目审核层级
        CategoryDto category = categoryService.get(en.getCid(),false);
        int auditCount = category.getAuditcount();

        //验证文章状态和操作
        validStatusAndOperate(en.getFlag(), operateType,auditCount);
        
        String validOperateUser1 = operateType.getName() + "操作时，操作人【" + userInfo.getName() + "】与文章作者【"+ en.getAuthor() +"】不能为同一个人";
        String validOperateUser2 = operateType.getName() + "操作时，操作人【" + userInfo.getName() + "】与文章二审人【"+ en.getReviewuser() +"】不能为同一个人";

        //对文章信息和状态进行修改更新
        LambdaUpdateWrapper<Article> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Article::getId, articleId);
        //如果进行的操作是设置或取消标签，单独进行处理
        if (operateType == CmsArticleOperateTypeEnum.SET_TAG || operateType == CmsArticleOperateTypeEnum.CANCEL_TAG) {
            //如果进行的操作是设置或取消标签，不对文章的更新时间和更新人进行设置
            //获取message中对应操作的标签值
            //获取本次设置或取消的标签对应的文字，方便在日志记录中使用；日志中重新对message进行赋值
            String tagName = "";
            if (!StringUtils.isBlank(message)) {
                try {
                    int setTagValue = Integer.parseInt(message);
                    if (setTagValue > 0x0) {
                        //处理得到最终的标签值
                        int srcTag = 0x0;
                        int destTag = 0x0;
                        if (en.getTags() != null && en.getTags() > 0x0)
                            srcTag = en.getTags();
                        //遍历标签枚举
                        for (CmsArticleTagEnum item : CmsArticleTagEnum.values()) {
                            //如果当前设置的标签是遍历的枚举，根据操作是设置还是取消进行取值；如果不是当前遍历的枚举获取原来的值进行累加
                            if (setTagValue == item.getIndex()) {
                                tagName = item.getName();

                                //如果是取消当前标签，不叠加当面枚举值
                                if (operateType == CmsArticleOperateTypeEnum.SET_TAG)
                                    destTag += item.getIndex();
                            } else {
                                if ((srcTag & item.getIndex()) == item.getIndex())
                                    destTag += item.getIndex();
                            }
                        }
                        //最终计算得到的标签值进行赋值
                        wrapper.set(Article::getTags, destTag);
                    }
                } catch (NumberFormatException ex) {
                    //转换错误不进行处理
                }
            }
            message = operateType.getName() + "-" + tagName;
        } else {
            //设置更新的列
            switch (operateType) {
                case DRAFT:
                    wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.DRAFT);
                    break;
                case AUDIT:
                    //提交审核
                    wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.AUDIT);
                    break;
                //case REVIEW_PASS:
                //    //二审通过操作时，判断操作人与起草人是否为同一个，是则提示
                //    if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                //    wrapper.set(Article::getFlag,CmsArticleStatusFlagEnum.REVIEW_PASS);
                //    break;
                //case REVIEW_NO_PASS:
                //    //二审不通过操作时，判断操作人与起草人是否为同一个，是则提示
                //    if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                //    wrapper.set(Article::getFlag,CmsArticleStatusFlagEnum.REVIEW_NO_PASS);
                //    break;
                case PASS:
                    ////审核通过操作时，先判断栏目审核层级
                    //if (auditCount == 0x1){
                    //    //判断操作人与起草人是否为同一个，是则提示
                    //    if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                    //}else if (auditCount == 0x2){
                    //    //判断操作人与二审人是否为同一个，是则提示
                    //    if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                    //    if (userInfo.getName().equals(en.getReviewuser())) return QCUnifyReturnValue.Warn(validOperateUser2);
                    //}else {
                    //    //
                    //}
                    //wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.PASS);
                    //2023-7，根据阳宗海现场沟通，简化流程：审核通过后自动发布
                    //wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.PUBLISH);
                    //2024-9-30 根据是否为二审修改状态
                    if (isreview){
                        //判断操作人与起草人是否为同一个，是则提示
                        if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                        //二审通过
                        wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.REVIEW_PASS);
                    }else {
                        //审核通过操作时，先判断栏目审核层级
                        if (auditCount == 0x1){
                            //判断操作人与起草人是否为同一个，是则提示
                            if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                        }else if (auditCount == 0x2){
                            //判断操作人与二审人是否为同一个，是则提示
                            if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                            if (userInfo.getName().equals(en.getReviewuser())) return QCUnifyReturnValue.Warn(validOperateUser2);
                        }else {
                            //
                        }
                        //审核通过直接发布
                        wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.PUBLISH);
                    }
                    break;
                case NO_PASS:
                    ////审核不通过操作时，先判断栏目审核层级
                    //if (auditCount == 0x1){
                    //    //判断操作人与起草人是否为同一个，是则提示
                    //    if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                    //}else if (auditCount == 0x2){
                    //    //判断操作人与二审人或者作者是否为同一个，是则提示
                    //    if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                    //    if (userInfo.getName().equals(en.getReviewuser())) return QCUnifyReturnValue.Warn(validOperateUser2);
                    //}else {
                    //    //
                    //}
                    //wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.NO_PASS);
                    //2024-9-30 根据是否为二审修改状态
                    if (isreview){
                        //判断操作人与起草人是否为同一个，是则提示
                        if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                        //二审不通过
                        wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.REVIEW_NO_PASS);
                    }else {
                        //审核不通过操作时，先判断栏目审核层级
                        if (auditCount == 0x1){
                            //判断操作人与起草人是否为同一个，是则提示
                            if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                        }else if (auditCount == 0x2){
                            //判断操作人与二审人或者作者是否为同一个，是则提示
                            if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                            if (userInfo.getName().equals(en.getReviewuser())) return QCUnifyReturnValue.Warn(validOperateUser2);
                        }else {
                            //
                        }
                        //审核不通过
                        wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.NO_PASS);
                    }
                    break;
                case PUBLISH:
                    //发布操作时，先判断栏目审核层级
                    if (auditCount == 0x1){
                        //判断操作人与起草人是否为同一个，是则提示
                        if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                    }else if (auditCount == 0x2){
                        //判断操作人与二审人是否为同一个，是则提示
                        if (userInfo.getName().equals(en.getAuthor())) return QCUnifyReturnValue.Warn(validOperateUser1);
                        if (userInfo.getName().equals(en.getReviewuser())) return QCUnifyReturnValue.Warn(validOperateUser2);
                    }else {
                        //
                    }
                    wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.PUBLISH);
                    break;
                case RECALL:
                    wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.RECALL);
                    break;
                case DELETED:
                    wrapper.set(Article::getFlag, CmsArticleStatusFlagEnum.DELETED);
                    break;
                default:
                    break;
            }
            wrapper.set(Article::getUptm, DateUtil.getNowDate());
            wrapper.set(Article::getUpuser, userInfo.getName());
            //如果操作时文章二审通过，设置二审时间、二审人和部门名称
            if (operateType == CmsArticleOperateTypeEnum.PASS && isreview == true){
                wrapper.set(Article::getReviewtm,DateUtil.getNowDate());
                wrapper.set(Article::getReviewuser,userInfo.getName());
                wrapper.set(Article::getReviewdept,userInfo.getDeptName());
            }
            //如果操作时文章审核通过发布，设置审核通过发布的时间、人和部门名称
            if (operateType == CmsArticleOperateTypeEnum.PASS || operateType == CmsArticleOperateTypeEnum.PUBLISH) {
                wrapper.set(Article::getPubtm, DateUtil.getNowDate());
                wrapper.set(Article::getPubuser, userInfo.getName());
                wrapper.set(Article::getPubdept, userInfo.getDeptName());
            }
        }

        if (repository.update(null, wrapper) < 0x1)
            return QCUnifyReturnValue.Warn("更新文章信息失败");

        //添加文章操作日志
        return articleLogService.add(articleId, operateType, message, userInfo);
    }

    /***
     * 物理删除指定文章，物理删除时不需要对已有文章信息进行修改，直接删除文章、日志
     *
     * @param articleId 文章ID
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2023/8/17
     */
    public String delete(int articleId) throws QCPromptException {
        articleLogService.deleteArticleLogs(articleId);

        repository.deleteById(articleId);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 验证指定文章的状态与操作是否符合要求，不符合抛出异常提示
     *
     * @param articleFlag 文章状态标记
     * @param operateType 操作类型
     * @return void
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    void validStatusAndOperate(CmsArticleStatusFlagEnum articleFlag, CmsArticleOperateTypeEnum operateType,int auditcount) throws QCPromptException {
        String msg = "文章状态为[" + articleFlag.getName() + "]，不能进行[" + operateType.getName() + "]操作";
        switch (articleFlag) {
            case DRAFT:
                //文章状态为草稿，不允许的操作：审核通过、审核不通过、发布、发布撤回、二审通过、二审未通过
                if (operateType == CmsArticleOperateTypeEnum.PASS
                        || operateType == CmsArticleOperateTypeEnum.NO_PASS
                        || operateType == CmsArticleOperateTypeEnum.PUBLISH
                        || operateType == CmsArticleOperateTypeEnum.RECALL 
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS 
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                )
                    throw new QCPromptException(msg);
                break;
            case AUDIT:
                //判断文章栏目审核层级
                if (auditcount == 0x0){
                    //编辑时保存自动发布
                    // 不允许的操作：审核通过、审核不通过、发布、发布撤回、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.PASS
                            || operateType == CmsArticleOperateTypeEnum.NO_PASS
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x1){
                    //文章状态为待审核，点击审核通过，直接发布
                    // 不允许的操作：提交审核、发布、发布撤回、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT 
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x2){
                    //文章状态为待审核，点击二审通过，进入终审
                    // 不允许的操作：提交审核、审核通过、审核不通过、发布、发布撤回
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            //||operateType == CmsArticleOperateTypeEnum.PASS
                            //|| operateType == CmsArticleOperateTypeEnum.NO_PASS
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL)
                        throw new QCPromptException(msg);
                }
                break;
            case REVIEW_NO_PASS:
                //文章状态为二审不通过
                if (auditcount == 0x0){
                    // 不允许的操作：提交审核、审核通过、审核不通过、发布、发布撤回、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            ||operateType == CmsArticleOperateTypeEnum.PASS
                            || operateType == CmsArticleOperateTypeEnum.NO_PASS
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x1){
                    //不允许的操作：二审通过、二审未通过
                    //if (operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                    //        || operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS)
                    //    throw new QCPromptException(msg);
                }else if (auditcount == 0x2){
                    //不允许的操作：提交审核、发布、发布撤回、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }
                break;
            case REVIEW_PASS:
                //文章状态为二审通过，不允许的操作：
                if (auditcount == 0x0){
                    //不允许的操作：审核通过、审核不通过、发布、发布撤回、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.PASS
                            || operateType == CmsArticleOperateTypeEnum.NO_PASS
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x1){
                    //不允许的操作：二审通过、二审未通过
                    //if (operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                    //        || operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS)
                    //    throw new QCPromptException(msg);
                }else if (auditcount == 0x2){
                    //不允许的操作：提交审核、发布、发布撤回
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL)
                        throw new QCPromptException(msg);
                }
                break;
            case NO_PASS:
                //文章状态为审核不通过，不允许的操作：发布、发布撤回
                if (operateType == CmsArticleOperateTypeEnum.PUBLISH
                        || operateType == CmsArticleOperateTypeEnum.RECALL)
                    throw new QCPromptException(msg);
                if (auditcount == 0x0){
                    //不允许的操作：审核通过、审核不通过、发布、发布撤回、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.PASS
                            || operateType == CmsArticleOperateTypeEnum.NO_PASS
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x1){
                    //不允许的操作：发布、发布撤回、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x2){
                    //不允许的操作：提交审核、发布、发布撤回
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            || operateType == CmsArticleOperateTypeEnum.PUBLISH
                            || operateType == CmsArticleOperateTypeEnum.RECALL)
                        throw new QCPromptException(msg);
                }
                break;
            case PASS:
                //文章状态为审核通过，不允许的操作：提交审核、发布撤回
                if (auditcount == 0x0){
                    //不允许的操作：提交审核、发布撤回、二审通过、二审不通过
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            || operateType == CmsArticleOperateTypeEnum.RECALL
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x1){
                    //不允许的操作：提交审核、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }else if (auditcount == 0x2){
                    //不允许的操作：提交审核、二审通过、二审未通过
                    if (operateType == CmsArticleOperateTypeEnum.AUDIT
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                            //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                    )
                        throw new QCPromptException(msg);
                }
                break;
            case PUBLISH:
                //文章状态为发布，不允许的操作：保存草稿、提交审核、审核通过、审核不通过、发布、二审通过、二审未通过
                if (operateType == CmsArticleOperateTypeEnum.DRAFT
                        || operateType == CmsArticleOperateTypeEnum.AUDIT
                        || operateType == CmsArticleOperateTypeEnum.PASS
                        || operateType == CmsArticleOperateTypeEnum.NO_PASS
                        || operateType == CmsArticleOperateTypeEnum.PUBLISH
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                )
                    throw new QCPromptException(msg);
                break;
            case RECALL:
                //文章状态为发布撤回，不允许的操作：提交审核、审核通过、审核不通过
                if (operateType == CmsArticleOperateTypeEnum.AUDIT
                        || operateType == CmsArticleOperateTypeEnum.PASS
                        || operateType == CmsArticleOperateTypeEnum.NO_PASS
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                )
                    throw new QCPromptException(msg);
                break;
            case DELETED:
                //文章状态为删除，不允许的操作：提交审核、审核通过、审核不通过、发布、发布撤回、删除、二审通过、二审未通过
                if (operateType == CmsArticleOperateTypeEnum.AUDIT
                        || operateType == CmsArticleOperateTypeEnum.PASS
                        || operateType == CmsArticleOperateTypeEnum.NO_PASS
                        || operateType == CmsArticleOperateTypeEnum.PUBLISH
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_PASS
                        //|| operateType == CmsArticleOperateTypeEnum.REVIEW_NO_PASS
                        || operateType == CmsArticleOperateTypeEnum.RECALL
                        || operateType == CmsArticleOperateTypeEnum.DELETED)
                    throw new QCPromptException(msg);
                break;
            default:
                throw new QCPromptException("文章状态标记类型错误");
        }
        switch (operateType) {
            case DRAFT:
                break;
            case AUDIT:
                break;
            case PASS:
                break;
            case NO_PASS:
                break;
            //case REVIEW_PASS:
            //    break;
            //case REVIEW_NO_PASS:
            //    break;
            case PUBLISH:
                break;
            case RECALL:
                break;
            case SET_TAG:
                break;
            case CANCEL_TAG:
                break;
            case DELETED:
                break;
            default:
                throw new QCPromptException("对文章的操作类型错误");
        }
    }

    /**
     * 获取指定文章的状态标记，用于判断是否能进行操作
     *
     * @param articleId 文章ID
     * @return 文章状态枚举
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    CmsArticleStatusFlagEnum getArticleStatus(Integer articleId) throws QCPromptException {
        if (articleId == null)
            throw new QCPromptException("指定查询的文章ID不能为空");

        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Article::getFlag);
        wrapper.eq(Article::getId, articleId);

        Article en = repository.selectOne(wrapper);
        if (en == null)
            throw new QCPromptException("指定查询的文章不存在");

        return en.getFlag();
    }

    /**
     * 添加文字操作日志记录
     *
     * @param articleId   文章ID
     * @param operateType 操作类型
     * @param message     操作信息，可以为null
     * @return 成功返回null
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public String addLog(Integer articleId, CmsArticleOperateTypeEnum operateType, String message) {
        return QCUnifyReturnValue.Success();
    }

    /**
     * 获取指定栏目ID的文章数量，不管文章的状态
     *
     * @param categoryId 栏目ID
     * @return 栏目下的文章数量
     * @author QuCheng Tech
     * @since 2023/5/27
     */
    public int getCategoryArticleCount(Integer categoryId) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Article::getId);
        wrapper.eq(Article::getCid, categoryId);

        //查询数据
        List<Article> list = repository.selectList(wrapper);
        if (list != null && list.size() > 0x0) {
            return list.size();
        }

        return 0x0;
    }

    /**
     * 获取指定栏目id集合的Top N条文章，不包含文章内容,文章有效状态--已发布
     *
     * @param categoryIds 栏目ID集合
     * @param count      最新文章数量
     * @return java.util.List<qc.module.cms.dto.article.ArticleDto>
     * @author QuCheng Tech
     * @since 2024/1/22
     */
    public List<ArticleDto> getCategoriesTopArticles(List<Integer> categoryIds,Integer count) throws QCPromptException {
        if (CollectionUtils.isEmpty(categoryIds))
            throw new QCPromptException("查询文章的栏目ID不能为空");

        //Top N有效值处理，如果不正确使用默认值
        if (count < 0x1)
            count = Get_Top_N_Article_Defalut_Count;

        //测试使用--根据传入的count构造N条文章数据进行返回
        //int pageNum = QCConstant.PAGEING_DEFAULT_PAGE_NUM;
        //int pageSize = count;
        //IPage<Article> page = new Page<>(pageNum, pageSize);
        //List<ArticleDto> result = new ArrayList<>();
        //for (int i = 1; i <= count; i++) {
        //    ArticleDto articleDto = new ArticleDto();
        //
        //    articleDto.setId(i);
        //    articleDto.setTitle(("文章标题文字内容" + i));
        //    articleDto.setCtype("0");
        //    articleDto.setKeywords("文章关键字信息" + i);
        //    articleDto.setSource("文章来源" + i);
        //    articleDto.setOdr(String.valueOf(i));
        //    articleDto.setFlag("0");
        //    articleDto.setCount(i * 10 + i);
        //
        //    result.add(articleDto);
        //}
        //
        //return result;

        //查询指定栏目id集合的Top N篇文章
        //注意--实际查询的时间去除content字段，不需要查询内容字段
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        //指定为查询不包含内容列
        wrapper.select(Article::getId, Article::getCid, Article::getTitle, Article::getCtype, Article::getKeywords,
                Article::getSource, Article::getAuthor, Article::getIntm, Article::getInuser, Article::getIndept,
                Article::getUptm, Article::getUpuser, Article::getPubtm, Article::getPubuser, Article::getPubdept,
                Article::getFlag, Article::getTags, Article::getCount);

        //栏目ID集合指定
        wrapper.in(Article::getCid, categoryIds);
        //状态必须为发布
        wrapper.eq(Article::getFlag, CmsArticleStatusFlagEnum.PUBLISH);

        //排序
        //先根据标签降序，文章置顶时标签为8，可以保证置顶文章排在最前
        wrapper.orderByDesc(Article::getTags);
        //再按发布时间降序，最新发布的文章排在前面
        wrapper.orderByDesc(Article::getIntm);

        //top-n
        wrapper.last("limit " + count);

        //查询
        List<Article> ens = repository.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(ens)) 
            return ArticleMapper.MAPPER.toDtoList(ens);
        return null;
    }
    
    /**
     * 获取指定栏目的Top N条文章，不包含文章内容,文章有效状态--已发布
     *
     * @param categoryId 栏目ID
     * @param count      最新文章数量
     * @return java.util.List<qc.module.cms.dto.article.ArticleDto>
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public List<ArticleDto> getCategoryTopArticles(Integer categoryId, int count) throws QCPromptException {
        
        List<Integer> cids = new ArrayList<>();
        cids.add(categoryId);

        return getCategoriesTopArticles(cids,count);
    }

    /**
     * 判断指定的ID是否存在
     *
     * @param id 文字ID
     * @return true表示已存在，false表示不存在
     * @author QuCheng Tech
     * @since 2023/5/29
     */
    public boolean hasIdExist(Integer id) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Article::getId);
        wrapper.eq(Article::getId, id);

        Article en = repository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /**
     * 生成记录ID，获取数据库表中的最大记录ID+1
     *
     * @return 生成记录ID
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer genereateId() {
        Integer maxRecordId = getMaxId();
        return maxRecordId + 1;
    }

    /**
     * 获取数据库表中的最大ID值，没有记录时返回0
     *
     * @return 返回数据库表中的最大ID值
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer getMaxId() {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Article::getId);
        wrapper.orderByDesc(Article::getId);
        Article en = repository.selectOne(wrapper);
        if (en != null)
            return en.getId();

        return 0x0;
    }

    /***
     * 根据数值获取对应的文章类型枚举，默认为富文本
     *
     * @param index 文章内容类型数值
     * @return qc.common.core.enums.CmsArticleContentTypeEnum
     * @author QuCheng Tech
     * @since 2023/7/30
     */
    CmsArticleContentTypeEnum getCmsArticleContentTypeEnum(Integer index) {
        if (index != null && index > 0x0) {
            for (CmsArticleContentTypeEnum item : CmsArticleContentTypeEnum.values()) {
                if (item.getIndex() == index) {//判断序号使用getIndex，判断内容使用getName
                    return item;
                }
            }
        }
        return CmsArticleContentTypeEnum.HTML;
    }


    /***
     * 根据数值获取对应的文章状态枚举，默认为草稿
     *
     * @param index 文章状态类型数值
     * @return qc.common.core.enums.CmsArticleStatusFlagEnum
     * @author QuCheng Tech
     * @since 2023/7/30
     */
    CmsArticleStatusFlagEnum getCmsArticleStatusFlagEnum(Integer index) {
        if (index != null && index > 0x0) {
            for (CmsArticleStatusFlagEnum item : CmsArticleStatusFlagEnum.values()) {
                if (item.getIndex() == index) {//判断序号使用getIndex，判断内容使用getName
                    return item;
                }
            }
        }
        return CmsArticleStatusFlagEnum.DRAFT;
    }

    /**
     * 移动文章到指定栏目
     *
     * @param dto:操作信息
     * @return String 成功返回null，失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/10/23
     */
    public String moveToCategory(MoveToCategoryDto dto) throws QCPromptException {
        //判断文章id是否为空
        if (dto.getIds().isEmpty()) {
            throw new QCPromptException("未选择文章");
        }
        //判断栏目是否存在
        if (!categoryService.hasIdExist(dto.getCid())) {
            throw new QCPromptException("指定栏目不存在");
        }
        //执行移动
        LambdaUpdateWrapper<Article> wrapper = new LambdaUpdateWrapper<>();
        //需要移动的文章ID
        wrapper.in(Article::getId, dto.getIds());
        //移动到指定栏目
        wrapper.set(Article::getCid, dto.getCid());

        //执行移动
        repository.update(null, wrapper);
        return QCUnifyReturnValue.Success();
    }

}
